import {AppNavigatorListener, AppNavigatorUtils, AppRoute} from "./app-navigator.utils.";
import {designComponent, nextTick, onBeforeUnmount, onMounted, reactive} from "plain-ui-composition";
import {delay} from 'plain-utils/utils/delay'
import {debounce} from "plain-utils/utils/debounce";
import {AppNavigatorPage} from "./app-navigator-page";

import {Mdc} from "../mdc/mdc";
import {persistLoading} from "../../../utils/persistLoading";
import {classnames} from "plain-utils/dom/classnames";

export const AppNavigator = (() => {
    const listener = {
        pathChange: [] as (AppNavigatorListener)[],
        hashChange: [] as (AppNavigatorListener)[],
        pageReady: [] as (AppNavigatorListener)[],
    }
    const state = reactive({
        route: AppNavigatorUtils.getRoute(),
        go: (path: string, hash?: string) => window.location.hash = encodeURIComponent(`${path}${!!hash ? '#' + hash : ''}`),
        event: {
            on: {
                onPathChange: (cb: AppNavigatorListener) => {
                    listener.pathChange.push(cb)
                    return () => listener.pathChange.splice(listener.pathChange.indexOf(cb), 1)
                },
                onHashChange: (cb: AppNavigatorListener) => {
                    listener.hashChange.push(cb)
                    return () => listener.hashChange.splice(listener.hashChange.indexOf(cb), 1)
                },
                onPageReady: (cb: AppNavigatorListener) => {
                    listener.pageReady.push(cb)
                    return () => listener.pageReady.splice(listener.pageReady.indexOf(cb), 1)
                },
            },
            emit: {
                onPathChange: (route?: AppRoute) => {
                    route = route || AppNavigatorUtils.getRoute()
                    listener.pathChange.forEach(cb => cb(route!))
                },
                onHashChange: (route?: AppRoute) => {
                    route = route || AppNavigatorUtils.getRoute()
                    listener.hashChange.forEach(cb => cb(route!))
                },
                onPageReady: (route?: AppRoute) => {
                    route = route || AppNavigatorUtils.getRoute()
                    listener.pageReady.forEach(cb => cb(route!))
                },
            },
        },
    })
    window.addEventListener('hashchange', () => {
        const route = AppNavigatorUtils.getRoute()
        const {path, hash} = route
        if (path !== state.route.path) {
            state.event.emit.onPathChange(route)
        } else if (hash !== state.route.hash) {
            state.event.emit.onHashChange(route)
        }
        state.route = route
    })
    return state
})();

export const AppNavigatorComponent = designComponent({
    name: 'navigator',
    props: {
        defaultPath: {type: String, required: true},
    },
    setup({props}) {

        onMounted(() => {
            if (!AppNavigator.route.path) {
                AppNavigator.route = {path: props.defaultPath, hash: ''}
                AppNavigator.event.emit.onPathChange(AppNavigator.route)
            }
        })

        const state = reactive({
            PageComponent: null as any,
            path: '',
        })

        const loading = persistLoading<string>({
            onSuccess: path => state.path = path,
            onFail: path => state.path = path,
        })

        const onPageMounted = async () => {
            await delay(200)
            loading.done()
            AppNavigator.event.emit.onPageReady()
        }

        const eject = AppNavigator.event.on.onPathChange(debounce(async ({path}) => {
            await nextTick()
            if (!path) {return}
            loading.start()

            let classes = classnames({
                'doc-page-full': path.indexOf('.full') > -1,
                'doc-page-entire': path.indexOf('.entire') > -1
            })
            /*加载md文档*/
            try {
                const content = (await import('@/doc/' + path + '.md')).default
                state.PageComponent = <Mdc content={content} class={classes}/>
                return loading.success(path)
            } catch (e) {/* do nothing */}

            /*加载组件*/
            try {
                const Component = (await import('@/doc/' + path + '.tsx')).default
                state.PageComponent = <Component class={classes}/>
                return loading.success(path)
            } catch (e) {
                /*do nothing*/
            }

            /*找不到渲染的页面*/
            console.error(`找不到页面:${path}`)
            const NotFount = (await import('../../../doc/not-found/not-found.full')).default
            state.PageComponent = <NotFount class="doc-page-full"/>
            return loading.fail(path)
        }, 100))

        onMounted(async () => {AppNavigator.event.emit.onPathChange(AppNavigator.route)})
        onBeforeUnmount(eject)

        return {
            render: () => {
                return (
                    <AppNavigatorPage
                        key={state.path}
                        onVnodeMounted={onPageMounted}>
                        {state.PageComponent}
                    </AppNavigatorPage>
                )
            }
        }
    },
})
